package main

import (
	"bytes"
	"crypto/aes"
	"encoding/hex"
	"fmt"
	"gitee.com/jn-qq/go-tools/progressbar"
	"io"
	"log"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"slices"
	"strconv"
	"strings"
)

type m3u8Flow struct {
	url     string
	baseUrl string
	key     string
}

func (m *m3u8Flow) ProductFunc() []any {
	var b []byte
	if strings.HasPrefix(m.url, "http://") || strings.HasPrefix(m.url, "https://") {
		// 设置m3u8 ts链接中的基本路径
		if m.baseUrl == "" {
			filepath.Base(m.url)
			m.baseUrl = strings.TrimSuffix(m.url, filepath.Base(m.url))
		}

		// 下载m3u8文件流
		response, err := http.Get(m.url)
		if err != nil {
			panic(err)
		}
		defer response.Body.Close()

		// 读取响应内容
		b, _ = io.ReadAll(response.Body)

	} else if _, err := os.Stat(m.url); err == nil {
		b, _ = os.ReadFile(m.url)
	} else {
		log.Fatal(m.url, "不存在")
	}

	if b == nil || len(b) == 0 {
		fmt.Println("未获取到文件内容：", m.url)
		return []any{}
	}

	var result []any
	n := 0
	for _, seg := range strings.Split(strings.ReplaceAll(string(b), "\n", ""), "#") {
		if seg == "" {
			continue
		}

		if strings.HasPrefix(seg, "EXT-X-KEY") {
			key := strings.TrimPrefix(strings.Split(seg, ",")[1], "URI=\"")
			m.key = strings.TrimSuffix(key, "\"")
		} else if strings.HasPrefix(seg, "EXTINF") {
			tsName := strings.Split(seg, ",")
			result = append(result, []any{strconv.Itoa(n), tsName[len(tsName)-1]})
			n++
		}
	}
	Bar = progressbar.NewBar("Running", len(result), ">")
	return result
}

func (m *m3u8Flow) ConsumerFunc(index int, item any) {
	tsObj := item.([]any)
	ts := tsObj[0].(string)
	var b []byte
	if tsObj[1] != nil {
		b = tsObj[1].([]byte)
	}

	//打印进度条
	Bar.PrintProgress(index + 1)

	// 保存文件
	file, _ := os.Create(filepath.Join(".cache", *fn, ts+".ts"))
	_, _ = file.Write(b)
	_ = file.Close()
}

func (m *m3u8Flow) HandleFunc(item any) any {
	ts := item.([]any)
	// 获取链接中文件名
	if _, err := os.Stat(filepath.Join(".cache", *fn, filepath.Base(ts[1].(string)))); err == nil {
		// 文件已存在
		return nil
	}
	// 获取文件字节
	response, err := http.Get(m.baseUrl + ts[1].(string))
	if err != nil {
		log.Fatal(err)
	}
	readAll, err := io.ReadAll(response.Body)
	if err != nil {
		log.Fatal(err)
	}

	return []any{ts[0], readAll}
}

func (m *m3u8Flow) ToMp4() {

	f, _ := os.Create(filepath.Join(".cache", "cache.txt"))

	// 读取目录
	entries, err := os.ReadDir(filepath.Join(".cache", *fn))
	if err != nil {
		log.Fatal(err)
	}
	// 获取文件名
	var files []int
	for _, entry := range entries {
		// 过滤目录项，只保留文件
		if !entry.IsDir() {
			filename := entry.Name()
			// 获取文件扩展名（区分大小写）
			if filepath.Ext(filename) == ".ts" {
				atoi, _ := strconv.Atoi(strings.Split(filename, ".")[0])
				files = append(files, atoi)
			}
		}
	}
	// 按文件名排序
	slices.Sort(files)

	for _, filename := range files {
		_, _ = f.WriteString(fmt.Sprintf("file '%s.ts'\n", filepath.Join(*fn, strconv.Itoa(filename))))
	}

	f.Close()

	ffmpeg, err := exec.LookPath("ffmpeg")
	if err != nil {
		log.Fatal(err)
	}
	cmd := exec.Command(ffmpeg,
		"-f", "concat",
		"-safe", "0", // 允许绝对路径（如果路径包含空格或特殊字符）
		"-loglevel", "debug",
		"-i", filepath.Join(".cache", "cache.txt"),
		"-c", "copy", // 直接复制流，不重新编码
		filepath.Join(".cache", *fn+".mp4"),
	)

	// 执行命令并捕获输出
	var stdout, stderr bytes.Buffer
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err = cmd.Run()
	if err != nil {
		panic(err)
	} else {
		_ = os.RemoveAll(filepath.Join(".cache", *fn))
	}

	fmt.Println(" done")
}

func (m *m3u8Flow) _aes(data []byte) []byte {

	cipher, _ := aes.NewCipher([]byte(m.key))
	cipherData, _ := hex.DecodeString(string(data))

	pt := make([]byte, len(cipherData))
	cipher.Decrypt(pt, cipherData)

	return pt

}
